﻿#ifndef _BASE_HPP_
#define _BASE_HPP_

#if defined(_WIN32)
#include <Windows.h>
#elif defined(__linux__)
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#endif

#define VERIFY(f)   ((void)(f))

#if defined(WIN32)
typedef HANDLE ThreadHandle;
#elif defined(__linux__)
typedef pthread_t ThreadHandle;
#endif

typedef unsigned long int ThreadId;

static bool GetCurrentModuleName(char* czPath,size_t len)
{
	bool bret = false;
#if defined(_WIN32) || defined(__CYGWIN__)	
	DWORD dwRet = GetModuleFileName(NULL,czPath,len);
	if (dwRet != 0)
	{
		char* p = czPath;
		while(*p != '\0')
		{
			if(*p == '\\')
			{
				*p = '/';
			}
			p++;
		}
		bret = true;
	}
#elif defined(__linux__) || defined(__LYNX)
	ssize_t t = readlink ("/proc/self/exe",czPath, len);
	if (t != -1)
	{
		bret = true;
	}
#endif
	return bret;
} 

typedef int (*ThreadStartRoutine)(void*);
typedef struct
{
	ThreadStartRoutine fStart;
	void* parm;
}ThreadParam;

#if defined(WIN32)
static DWORD WINAPI ThWokerThread(void* param)
#elif defined(__linux__)
static void* ThWokerThread(void* param)
#endif
{
	ThreadParam Info = *(ThreadParam*)param;
	delete ((ThreadParam*)param);
	int r = Info.fStart(Info.parm);

#if defined(WIN32)
	return r;
#elif defined(__linux__)
	return (void*)(long)r;
#endif
}

inline bool CreateNewThread(ThreadHandle& threadHandle,ThreadStartRoutine fStart, void* parm, unsigned int stackSize,ThreadId pID)
{
	ThreadParam* pInfo = new ThreadParam;
	pInfo->fStart = fStart;
	pInfo->parm = parm;

#if defined(WIN32)
	threadHandle = CreateThread(NULL, stackSize, ThWokerThread, pInfo, 0, &pID);
	if (threadHandle == NULL)
	{
		delete pInfo;
		return false;
	}

#elif defined(__linux__)
	int r = -1;
	if (stackSize > 0)
	{
		pthread_attr_t att;
		r = pthread_attr_init(&att);
		if(r == 0)
		{
			r = pthread_attr_setstacksize(&att, stackSize);
			if(r == 0)
				r = pthread_create(&threadHandle, &att, ThWokerThread, pInfo);
			pthread_attr_destroy(&att);
		}
	}
	else
	{
		r = pthread_create(&threadHandle, NULL, ThWokerThread, pInfo);
	}

	if(r != 0)
	{
		delete pInfo;
		return false;
	}

	pID = threadHandle;

#endif

	return true;
}

inline void CloseThread(ThreadHandle threadHandle)
{
#if defined(WIN32)
	VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(threadHandle, INFINITE));
	VERIFY(CloseHandle(threadHandle));
#elif defined(__linux__)
	VERIFY(0 == pthread_join(threadHandle, NULL));
#endif
}

inline int CaleFormatLen(const char * _Format, va_list _ArgList)
{
#if defined(_WIN32)
	return _vscprintf(_Format, _ArgList);
#elif defined(__linux__)
	va_list argList;
	va_copy(argList, _ArgList);
	int retval = vsnprintf(NULL, 0, _Format, argList);
	va_end(argList);
	return retval;
#endif
}

#endif
